import { mapMutations, mapGetters } from 'vuex'
import { createComponent } from '@/packages'
import { loadingStart, loadingFinish, setComponentPosition } from '@/utils'
import { throttle, cloneDeep } from 'lodash'

let mixins = {
  computed: {
    ...mapGetters(['editCanvas', 'editCanvasConfig', 'targetChart', 'componentList']),
    ...mapGetters('chartEdit', ['fetchTargetIndex']),
  },
  methods: {
    ...mapMutations('chartEdit', ['setTargetSelectChart', 'setEditCanvas', 'addComponentList', 'setMousePosition', 'setTargetHoverChart']),
    // * 不拦截默认行为点击
    mousedownHandleUnStop (e, item) {
      if (item) {
        this.setTargetSelectChart({ id: item.id })
        return
      }
      this.setTargetSelectChart({ id: undefined })
    },
    // 拖拽到编辑区域里
    async dragHandle (e) {
      e.preventDefault()
      try {
        loadingStart()
        // 获取拖拽数据
        const drayDataString = e.dataTransfer.getData('ChartData')
        if (!drayDataString) {
          loadingFinish()
          return
        }
        // 修改状态
        this.setEditCanvas({ key: 'isCreate', value: false })
        const dropData = JSON.parse(drayDataString)
        if (dropData.disabled) return
        // 创建新图表组件
        let newComponent = await createComponent(dropData)
        if (dropData.redirectComponent) {
          dropData.dataset && (newComponent.option.dataset = dropData.dataset)
          newComponent.chartConfig.title = dropData.title
          newComponent.chartConfig.chartFrame = dropData.chartFrame
        }
        setComponentPosition(newComponent, e.offsetX - newComponent.attr.w / 2, e.offsetY - newComponent.attr.h / 2)
        this.addComponentList({ componentInstance: newComponent, isHead: false, isHistory: true })
        this.setTargetSelectChart({ id: newComponent.id })
        loadingFinish()
      } catch (error) {
        loadingFinish()
        this.$message.warning(`图表正在研发中, 敬请期待...`)
      }
    },
    // * 进入拖拽区域
    dragoverHandle (e) {
      e.preventDefault()
      e.stopPropagation()
      if (e.dataTransfer) e.dataTransfer.dropEffect = 'copy'
    },
    // * 框选
    mousedownBoxSelect (e, item) {
      if (e.which == 2) return
      if (window.$KeyboardActive?.space) return
      this.mousedownHandleUnStop(e)

      // 记录点击初始位置
      const startOffsetX = e.offsetX
      const startOffsetY = e.offsetY
      const startScreenX = e.screenX
      const startScreenY = e.screenY

      // 记录缩放
      const scale = this.editCanvas.scale
      this.setMousePosition({ x: undefined, y: undefined, startX: startOffsetX, startY: startOffsetY })
      // 移动框选
      const mousemove = throttle(moveEvent => {
        // 取消当前选中
        this.setTargetSelectChart({})
        this.setEditCanvas({ key: 'isSelect', value: true })

        // 这里先把相对值算好，不然组件无法获取 startScreenX 和 startScreenY 的值
        const currX = startOffsetX + moveEvent.screenX - startScreenX
        const currY = startOffsetY + moveEvent.screenY - startScreenY
        this.setMousePosition({ x: currX, y: currY })

        // 计算框选的左上角和右下角
        const selectAttr = {
          // 左上角
          x1: 0,
          y1: 0,
          // 右下角
          x2: 0,
          y2: 0
        }
        if (currX > startOffsetX && currY > startOffsetY) {
          // 右下方向
          selectAttr.x1 = startOffsetX
          selectAttr.y1 = startOffsetY
          selectAttr.x2 = Math.round(startOffsetX + (moveEvent.screenX - startScreenX) / scale)
          selectAttr.y2 = Math.round(startOffsetY + (moveEvent.screenY - startScreenY) / scale)
        } else if (currX > startOffsetX && currY < startOffsetY) {
          // 右上方向
          selectAttr.x1 = startOffsetX
          selectAttr.y1 = Math.round(startOffsetY - (startScreenY - moveEvent.screenY) / scale)
          selectAttr.x2 = Math.round(startOffsetX + (moveEvent.screenX - startScreenX) / scale)
          selectAttr.y2 = startOffsetY
        } else if (currX < startOffsetX && currY > startOffsetY) {
          selectAttr.x1 = Math.round(startOffsetX - (startScreenX - moveEvent.screenX) / scale)
          selectAttr.y1 = startOffsetY
          selectAttr.x2 = startOffsetX
          selectAttr.y2 = Math.round(startOffsetY + (moveEvent.screenY - startScreenY) / scale)
          // 左下方向
        } else {
          // 左上方向
          selectAttr.x1 = Math.round(startOffsetX - (startScreenX - moveEvent.screenX) / scale)
          selectAttr.y1 = Math.round(startOffsetY - (startScreenY - moveEvent.screenY) / scale)
          selectAttr.x2 = startOffsetX
          selectAttr.y2 = startOffsetY
        }

        // 遍历组件
        this.componentList.forEach(item => {
          if (!this.targetChart.selectId.includes(item.id)) {
            // 处理左上角
            let isSelect = false
            const { x, y, w, h } = item.attr
            const targetAttr = {
              // 左上角
              x1: x,
              y1: y,
              // 右下角
              x2: x + w,
              y2: y + h
            }
            // 全包含则选中
            if (
              targetAttr.x1 - selectAttr.x1 >= 0 &&
              targetAttr.y1 - selectAttr.y1 >= 0 &&
              targetAttr.x2 - selectAttr.x2 <= 0 &&
              targetAttr.y2 - selectAttr.y2 <= 0 &&
              !item.status.lock &&
              !item.status.hide
            ) {
              isSelect = true
              this.setTargetSelectChart({ id: item.id, push: true })
            }
          }
        })
      }, 30)

      // 鼠标抬起
      const mouseup = () => {
        // 鼠标抬起时，结束mousemove的节流函数，避免选框不消失问题
        mousemove.cancel()
        this.setEditCanvas({ key: 'isSelect', value: false })
        this.setMousePosition({ x: 0, y: 0, startX: 0, startY: 0 })
        document.removeEventListener('mousemove', mousemove)
        document.removeEventListener('mouseup', mouseup)
      }
      document.addEventListener('mousemove', mousemove)
      document.addEventListener('mouseup', mouseup)
    },
    // * 移动锚点
    MousePointHandle (e, point, attr) {
      e.stopPropagation()
      e.preventDefault()

      // 设置拖拽状态
      this.setEditCanvas({ key: 'isDrag', value: true })
      const { scale } = this.editCanvas

      const itemAttrX = attr.x
      const itemAttrY = attr.y
      const itemAttrW = attr.w
      const itemAttrH = attr.h

      // 记录点击初始位置
      const startX = e.screenX
      const startY = e.screenY

      // 记录初始位置
      this.setMousePosition({ x: startX, y: startY })

      const mousemove = throttle((moveEvent) => {
        this.setMousePosition({ x: moveEvent.screenX, y: moveEvent.screenY })

        let currX = Math.round((moveEvent.screenX - startX) / scale)
        let currY = Math.round((moveEvent.screenY - startY) / scale)

        const isTop = /t/.test(point)
        const isBottom = /b/.test(point)
        const isLeft = /l/.test(point)
        const isRight = /r/.test(point)

        const newHeight = itemAttrH + (isTop ? -currY : isBottom ? currY : 0)
        const newWidth = itemAttrW + (isLeft ? -currX : isRight ? currX : 0)

        attr.h = newHeight > 0 ? newHeight : 0
        attr.w = newWidth > 0 ? newWidth : 0
        attr.x = itemAttrX + (isLeft ? currX : 0)
        attr.y = itemAttrY + (isTop ? currY : 0)
      }, 50)

      const mouseup = () => {
        this.setEditCanvas({ key: 'isDrag', value: false })
        this.setMousePosition({ x: 0, y: 0, startX: 0, startY: 0 })
        document.removeEventListener('mousemove', mousemove)
        document.removeEventListener('mouseup', mouseup)
      }

      document.addEventListener('mousemove', mousemove)
      document.addEventListener('mouseup', mouseup)
    },
    // *  Click 事件, 松开鼠标触发
    mouseClickHandle (e, item) {
      e.preventDefault()
      e.stopPropagation()
      // 若此时按下了 CTRL, 表示多选
      if (window.$KeyboardActive?.ctrl) {
        // 若已选中，则去除
        if (this.targetChart.selectId.includes(item.id)) {
          const exList = this.targetChart.selectId.filter(e => e !== item.id)
          this.setTargetSelectChart({ id: exList })
        } else {
          this.setTargetSelectChart({ id: item.id, push: true })
        }
      }
    },
    // * 进入事件
    mouseenterHandle (e, item) {
      e.preventDefault()
      e.stopPropagation()
      if (!this.editCanvas.isSelect) {
        this.setTargetHoverChart(item.id)
      }
    },
    // * 移出事件
    mouseleaveHandle (e, item) {
      e.preventDefault()
      e.stopPropagation()
      this.setEditCanvas({ key: 'isDrag', value: false })
      this.setTargetHoverChart(undefined)
    },
    // * 按下事件（包含移动事件）
     mousedownHandle (e,item){
      e.preventDefault()
      e.stopPropagation()
      if (item.status.lock) return
      // onClickOutSide()
      // 选中当前目标组件
      this.setTargetSelectChart({id:item.id})
      const {scale} = this.editCanvas
      const canvasWidth = this.editCanvasConfig.width
      const canvasHeight = this.editCanvasConfig.height
  
      // 记录图表初始位置和大小
      const targetMap = new Map()
      this.targetChart.selectId.forEach( (id) => {
        const index = this.fetchTargetIndex(id)
        if (index !== -1) {
          const { x, y, w, h } =  this.componentList[index].attr
          targetMap.set(id, { x, y, w, h })
        }
      })
  
      // 记录点击初始位置
      const startX = e.screenX
      const startY = e.screenY
  
      // 记录历史位置
      let prevComponentInstance = []
      this.targetChart.selectId.forEach( (id) => {
        if (!targetMap.has(id)) return
  
        const index = this.fetchTargetIndex(id)
        // 拿到初始位置数据
        prevComponentInstance.push(cloneDeep(this.componentList[index]))
      })
  
      // 记录初始位置
      this.setMousePosition({x:undefined, y:undefined, startX, startY})
  
      // 移动-计算偏移量
      const mousemove = throttle(moveEvent => {
        this.setEditCanvas({key:'isDrag', value:true})
        this.setMousePosition({x:moveEvent.screenX, y:moveEvent.screenY})
        // 当前偏移量，处理 scale 比例问题
        let offsetX = (moveEvent.screenX - startX) / scale
        let offsetY = (moveEvent.screenY - startY) / scale
  
        this.targetChart.selectId.forEach((id) => {
          if (!targetMap.has(id)) return
  
          const index = this.fetchTargetIndex(id)
          // 拿到初始位置数据
          const { x, y, w, h } = targetMap.get(id)
          const componentInstance = this.componentList[index]
  
          let currX = Math.round(x + offsetX)
          let currY = Math.round(y + offsetY)
  
          // 要预留的距离
          const distance = 50
  
          // 基于左上角位置检测
          currX = currX < -w + distance ? -w + distance : currX
          currY = currY < -h + distance ? -h + distance : currY
  
          // 基于右下角位置检测
          currX = currX > canvasWidth - distance ? canvasWidth - distance : currX
          currY = currY > canvasHeight - distance ? canvasHeight - distance : currY
          if (componentInstance) {
            componentInstance.attr = Object.assign(componentInstance.attr, {
              x: currX,
              y: currY
            })
          }
        })
        return
      }, 20)
  
      const mouseup = () => {
        try {
          this.setMousePosition({x:0, y:0, startX:0, startY:0})
          this.setEditCanvas({key:'isDrag', value:false})
          // 加入历史栈
          if (prevComponentInstance.length) {
            this.targetChart.selectId.forEach(id => {
              if (!targetMap.has(id)) return
              const index = this.fetchTargetIndex(id)
              const curComponentInstance = this.componentList[index]
              // 找到记录的所选组件
              prevComponentInstance.forEach(preItem => {
                if (preItem.id === id) {
                  preItem.attr = Object.assign(preItem.attr, {
                    offsetX: curComponentInstance.attr.x - preItem.attr.x,
                    offsetY: curComponentInstance.attr.y - preItem.attr.y
                  })
                }
              })
            })
  
            const moveComponentInstance = prevComponentInstance.filter(
              item => item.attr.offsetX !== 0 && item.attr.offsetY !== 0
            )
            // moveComponentInstance.length && chartEditStore.moveComponentList(moveComponentInstance)
          }
          document.removeEventListener('mousemove', mousemove)
          document.removeEventListener('mouseup', mouseup)
        } catch (err) {
          console.log(err)
        }
      }
  
      document.addEventListener('mousemove', mousemove)
      document.addEventListener('mouseup', mouseup)
    }
  }
}
export default mixins